﻿// -----------------------------------------------------------------------
// <copyright file="Forth.cs" company="G.W. van der Vegt">
// SharpForth is inspired by JonesForthInC v1.48 and bb4wForth.
// </copyright>
// -----------------------------------------------------------------------

/* -------------------------------------------------------
 * Purpose: SharpForth
 * Author:  Ir. G.W. van der Vegt
 * For:     Swiss Management N.V.
 *
 * Note:    This Forth Interpreter is writen in pure managed C# (and Forth itself as usual).
 *          In constrast to other interpreters it does not use assembly language.
 *          
 *          The downside is off-course that some featurs are not available (like unrestricted 
 *          memory access).
 *          
 *          The built-in Forth Words are written in C# and where possible Forth.
 * -------------------------------------------------------
 * ddmmyyyy remark
 * -------- ----------------------------------------------
 * ddmmyyyy-Initial version.
 *         -Defined DOCOL as a Special Index so we can detect it inside Execute() for now and implement the DOCOL Constant.
 *         -True is defined as -1 instead of 1.
 *         -Keyboard and Console.
 *         -Switched to ConsoleDialog.
 *         -Interpreting Words/Definitions.
 *         -Bind to Console.
 * 01082013-Improved Code.
 * 03082013-Got Compiler working.
 * 04082013-Suppress error when Locating word (and it's a number).
 * 06082013-Changed search direction of Locate so it starts with the Latest Word (and we can replace).
 *         -Implemented EMIT.
 * 07082013-Implemented BRANCH/0BRANCH.
 *         -Implemented some address related words by using the lower 2 bits of an address and traget area (DEF/RSP/PARAM).
 *         -Improved SEE
 *         -Added (0)BRANCH to Invoke of Words.
 *         -Implemented IMMEDIATE Word (Toggles F_IMMED Flag).
 * 09082013-Added word_buffer as List<Char> as 4th type of memory.
 *         -Strings are now kept on this buffer.
 *         -Added some new error messages
 *         -Improved SEE (if word is not found).
 *         -Strings are removed from buffer when no longer neccesary (from top only).
 *         -Above fixed bug in interpreting: 'WORD 10 NUMBER .'.
 *         -Started on correcting printout for BASE.
 *         -Added methods to convert from/to lots of bases (up to base 36).
 *         -Removed Convert.ToInt32() calls.
 *         -Got BASE working with actual storage inside the Definition (mostly in Forth).
 *          Tricky but it works.
 *          It all depends on where the address pointer gets it's final value.
 *         -Changed all PARAM_STACK.Pop() to PopPSP() calls (and test for an empty stack).
 *         -Set BUILT-IN to the correct value.
 *         -Added ['] (Tick) to SEE Code, so it prints correctly now.
 *         -Got IF compiling.
 *         -Update DP during , Word.
 *         -Verified working of IMMEDIATE.
 *         -DP and HERE seem to be working.
 *         -['] Tick is now hybrid (in compile mode inside Execute, in interpret mode normal Forth Code).
 *         -IF/THEN Starts to work
 *          Syntax : 10 TRUE  IF 1 + THEN . ; works  -> 11
 *          Syntax : 10 FALSE IF 1 + THEN . ; works  ->  9
 * 10082013-Fixed error in BRANCH (jumped one to far) and had to adjust offsets in LATEST, DP and BASE
 *         -Added more control structures
 *         -Fixed typo in != (was =).
 *         -Embedded ( x -- y ) type comments are now working.
 *         -Added [COMPILE].
 *         -Fixed UNLESS.
 *         -Moved Words into Separate Class.
 *         -Used Lazy<DictionaryEntry> and Secondary List to load Words. We can now load in
 *          correct order without words getting initialized early.
 * 12082013-Fixed some typo's in Library.
 *         -Added Description Attrinbute to Library Strings.
 *         -Added A2I(), A2D() and I2A() and replaced code in Words with it.
 *         -Added LocateI().
 *         -Implemented S" in Immediate Mode (using the STRING_BUFFER).
 *          But it fails as TELL expects the string inside a word. So we
 *          have to compile it into nameless words Definition (and add a branch 
 *          to skip if it's accidently executed).
 * 14082013-Lots of trouble with plastic showing duplicate branches.
 *         -Simplified input (move code from console to Forth and 
 *          swapped Stack<Char> for Queue<Char> so it's possible to add characters 
 *          in the correct order without reversing strings).
 *         -Fixed input, OK and prompt (hopefully).
 *         -Added EXIT to DictionaryEntry.Execute(). This made ." working, 
 *          the only word sofar using EXIT.
 * 15082013-Added RDEPTH, .RSTACK, PRINT-STACK-TRACE.
 *         -Moved EXIT into Execute() as just a break; statement.
 *         -Added CurrentWordt property.
 *         -Manage Return Stack in Execute(), seems to work fine.
 * 16082013-Added FORGET.
 *         -Added SYNTAX and SyntaxAttribute.
 *         -Added Syntax to Library too (need to split up into individual words).
 *         -Split library into separate strings and applied (some)  Syntax attributes.
 *         -Added Library Syntax to SYNTAX Word.
 *         -Added U.R. U. and .R (and a hidden UDOT).
 *         -Added RECURSE (and it works)!
 *         -Corrected ROT, -ROT, /MOD and U/MOD (return values in incorrect order).
 *         -Added CASE, OF, ENDOF and ENDCASE.
 *         -Added ABS and 2OVER.
 *         -Removed most hardcoded string from DictionaryEntry.Execute and the Forth Word SEE
 *          by using Words.XXX.Value.Name.
 *         -Removed case statement for "NEXT" in Execute as it's not a Forth 
 *          Word and thus will never execute.
 *         -Added WELCOME.
 *         -Added LOAD-FILE ( addr len -- 0 if success, -1 if fail).
 *          Input is Added to the Input Queue.
 *          
 *         -Added CONSTANT.
 *         -Added VARIABLE. 
 *          Used pattern like BASE so no DODOES but a 
 *          hardcoded refence to the VARIABLE address to be 
 *          followed and a BRANCH over the storage area to the EXIT.
 * 17082013-Recoded VARIABLE so it uses EXIT followed by a dummy word DATA-MARKER.
 *          DATA-MARKER makes SEE output a numeric array of cells instead dissasembling it.
 *         -Implemented CELLS (not as 4* but as 1* as SharpForth only addresses Int32's).
 *         -Moved the WORD from DOCOLON to CREATE so it can be used stand-alone too.
 *         -Improved ALLOT so turns an empty Forth Word (like CREATE TEN) into a VARIABLE 
 *          before extending storage. This way both VARIABLE TEN and CREATE TEN can be ALLOT'ed
 *          with the difference that VARIABLE has one CELL more as it's prefilled with one.
 *         -Tested CREATE TEN 5 CELLS ALLOT.
 *         -Corrected CELLS to read 4* again.
 *         -ALLOT now round up toa 4 fold and divides by 4 to get the actual number of CELLS.
 *          This allows CREATE X 3 ALLOT to be equal to CREATE X 1 CELLS ALLOT.
 * 18082013-Started on DO/LOOP suite of flow control.     
 *         -Added ID.
 * 19082013-Swapped memory model from:
 * 
 *          //! +------------------------+------------------+--------------+
 *          //! | DICTIONARY INDEX       | DEFINITION INDEX | TARGET FLAGS |
 *          //! |                        |                  |              |
 *          //! +--- (16 bits) ----------+- (14 bits) ------+- (2 bits) ---+
 *          
 *          to:
 *          
 *          //! +--------------+------------------------+------------------+
 *          //! | TARGET FLAGS | DICTIONARY INDEX       | DEFINITION INDEX |
 *          //! |              |                        |                  |
 *          //! +- (2 bits) ---+--- (14 bits) ----------+- (16 bits) ------+
 *          
 *          in order to allow byte size addressing.
 *
 *         -Corrected .STACK.
 *         -Corrected CONSTANT.
 *
 *         -FAILURES Sofar: .R
 *         -ISSUES: Look into CREATE invokes (no WORD in front).
 *         -        SEE of a Constant produces a CLS.
 *
 * 20082013-Added TRACE, TRACEON and TRACEOFF.
 *         -Corrected return values of BaseToDecimal to mimic bbwForth.
 *         -Corrected return values of NUMBER (partial or full number + number of unparsed characters).
 *         -Corrected .R by using bbwForth code (mainly a -ROT was changed to ROT).
 *         -Formatted TRACE output (and incorporated the PARAM_STACK).
 *         -Added try {} catch {} around INTERPRET inside QUIT 
 *          so SharpForth nicely restarts on a error like a divide by 0.
 *         -Added VALUE, TO and +TO in immediate mode.
 *         
 *          Sample code:
 *              20 VALUE val    creates VAL with initial value 20",
 *              val             pushes the value (20) directly on the stack",
 *              30 TO val       updates VAL, setting it to 30",
 *              x +TO val       adds x to VAL
 *          
 *         -Added compile mod esupport to VALUE, TO and +TO.
 *         -Clear SysInternals DebugView too in Forth CLS Word.
 * 21082013-Added DOCOL to TRACEON/TRACEOFF and other variables like BASE.
 *         -Corrected offset of Variable storage to be 24.
 *          Now these variables also disassembly properly once more.
 * 22082013-Changed Description Attribute into a more dedicated WordName Attribute
 *         -Added check if DOCOL is missing at the start of Defintions.
 *         -Updated lots of Syntax attributes and removed duplicate wordnames from these attributes.
 *         -Added TYPE as alias for TELL.
 *         -Removed WORD_BUFFER_SIZE.
 *         -Improved reading of input.
 *         -Added check for empty input queue to DoInputAvailable().
 *         -Added errormessage if LOAD-FILE fails to locate the file.
 *         -Added skipping of CR when reading (file) input.
 * 23082013-Started on DO LOOP.
 *         -Added Click-Once Installer (just zip the publish folder with *.application in the root).
 *         -See http://blogs.msdn.com/b/codeplex/archive/2010/07/13/clickonce-releases.aspx.
 *         -Updated Copyright to match License.
 *         -Added Int32ByteUnion for Byte Addressing.
 *         -Implemented C! C@ C@C! and CMOVE. With the restriction that they are not allowed to cross Forth Word Definition boundaries.
 *         -Implemented CFA> (note that 0 is both an error and word 0).
 *         
 *          Test code:
 *              WORD DOUBLE FIND >CFA 
 *              CFA> .
 *              and watch debug output).
 *          
 *         -Added Hidden XYYZ Forth Word to protect address 0.
 *         -Added (LOOP) and LOOP.
 *         -Implemented actual (LOOP) and (+LOOP) code inside DictionaryEntry.Execute as it influences the execution order.
 *         -Added I.
 *         -Removed LF and change CR so it emits \r\n (hehe running Windows!).
 *         -Added BINARY and OCTAL.
 *         -Added J and UNLOOP.
 *         
 *          Test code: 
 *              ': T 15 0 DO I 5 = IF UNLOOP EXIT THEN I . 32 EMIT LOOP ;' 
 *              T
 *              0 1 2 3 4 OK
 *
 *         -Counter now at 200 Forth Words.
 *         -Fixed SEE for (LOOP) and (+LOOP) by showing the Jump Offset.
 *         -Added LEAVE.
 *         -Disabled VERSION Word.
 *         -Changed Type of SharpForthVersion into a Version and enabled VERSION.       
 *         -Started debugging tester.fr's } Word.
 *         -Added tester.fr from bb4wForth?
 * 24082013-Corrected DEPTH for itself (so substracted one).
 *         -DEPTH was mistakingly marked as IMMEDIATE.
 *         
 *         -Added FLUSH, clears the input queue.
 *         -Corrected +! and -! (left a value on the Parameter Stack).
 *         -Rewrote tester Script so it works and produces nice looking output.
 *         -Stil some compilation issues it seems.
 *         -Made SEE work in compiled words for simple words only (so no TICK and code generation etc).
 *          It works ok for VALUES etc.
 *         -Corrected INVERT.
 *         -Added some 52 JonesForthInC coretests to test.f 
 *         
 * 25082013-Changed inner workings of DecimalToBase() to use an INT64.
 * 26082013-Added U> and U< from bb4wForth.
 *         -Worked on test suite.
 *         -Rewrote some unsigned Forh Words to use Int64 or Uint32 internally. 
 *         -Moved PICK from Libraty to Words as DSP@ access to the stack will fail.
 *         -Corrected 2OVER (used PICK).
 *         -Corrected 2SWAP.
 *         -Added RSHIFT and LSHIFT to test script.
 *         -Added 2*, 2/  and U2/ from b4wForth.
 *         -173 Test's Passed.
 *         
 * 27082013-Linked version to either AssemblyInfo or ClickOnce Release depending on method of deployment.
 *         -Corrected ' (TICK)
 *         -Added bb4wForth EXECUTE.
 *         -Added VERSION again as 100*major+revision.
 *          Had to disable some due to missing bb4wForth Words.
 *         -Corrected (+LOOP) end criteria (using the Sign of XOR or index-limit+n and index-limit).
 *         -Added more core tests (now counter at 300 Test's Passed). 
 *         -Total number of tests in original core.fr is around 639.
 *         -Added MULDIV and MULDIVMOD (cannot writec the actual Forth Words here as it ruins comments).
 *         
 * 02092013-Added LOAD-URL to load plain text Forth directly from the web.
 *         -Added Least Common Denominator to examples.f
 *         -Added spellnumber.f (or http://www.dst-corp.com/james/JonesForthInC/SPELLNUMBER.f.txt)
 *         -Added regexp.fs (Fails).
 *         
 * 05092013-Added POSTPONE.
 *         -Enabled POSTPONE tests in test.f.
 *         -Added EVALUATE (first version).
 *         -Enabled EVALUATE tests in test.f.
 *         -320 Test's Passed.
 *         
 * 06082013-Finally corrected ['] to be an IMMEDIATE Forth Word 
 *          (found a good explaination other that machine code).
 *         -Removed ['] from DictionaryEntry.Execute().
 *         -Tick once more working in both COMPILE and IMMEDIATE mode.
 *         -Added some more tests (and fixup for them).
 *          Note that: 
 *          
 *              1) HERE 1 ALLOT does not work
 *              2) 2@ and @! are not allowed to cross word boundaries
 *              3) CELL+ will not get you into a next word.
 *              4) VARIABLE VAR gives you once cell storage.
 *              5) VARIABLE VAR 1 ALLOT gives you two cells storage.
 *              
 *         -Added ? as an Alias for @ .
 *         -New ClickOnce Release (Build 6).
 *         
 *         -Aligned TRACE output better (splitted again to before and after stack).
 *         -Corrected XML Documentation.
 *         -Removed most warnings.
 *         -Disabled some to verbose Debug Output.
 *         
 *         -Made Forth Words case insensitive.
 *         -Added LIST-FILES.
 *         
 * 08092013-Implemented S" in immediate mode (it will compile a hidden, nameless word containing the string).
 *          So 

 *              S" This is a String" TYPE 
 *              
 *          will work and create a nameless word with the string inside.
 *          
 *              SEE {noname}
 *              
 *          will show the definition of last nameless word defined.
 *          Finally
 *          
 *              FORGET {noname}
 *              
 *          will forget all words up to the last nameless word defined.
 *          
 *         -Added support for nameless words ({noname}) in WORDS and FORGET.
 *         -Show number of hidden or nameless words that are forgotten (if any).
 *         
 * 09092013-Started on floating point numbers.
 *         -Added FDEPTH, .FSTACK, /F, FLOAT, F., FIX, FCLEAR.
 *         -Added F+, F-, F/, F*, F**.
 *         
 * 10902013-Started on Ansi Forth 94 compliance.
 *         -Added WordSet Attributes to define the set a word belongs to.
 *         -Added SET word that shows the WordSet of a Word together with it's description.
 *         -Replaced calls like:
 *         
 *              Forth.Dictionary[Forth.LocateI("WORD")].Invoke();
 *              
 *          by a much faster:
 *          
 *              FIND.Value.Invoke();
 *          
 *         -Started on making the Forth syntax documentation equal to Ansi Forth94.
 *         -Added TIME&DATE.
 *         -Added ELAPSED (ie not MS which is a Delay).
 *         
 * 11092013-Moved adding DOCOL to CREATE (and removed it from VARIABLE, CONSTANT and some more places).
 *         -Rewrote LEAVE-SP to VARIABLE.
 *         -Added DOES> as a hybrid word (runtime resided in in Dictionary.Execute()).
 *         -DODOES is not needed.
 *         -Removed JoneForth demo words DOUBLE and QUADRUPLE.
 *         
 * 12092013-Corrected behavior of Forth Words not starting with DOCOL to pushing their address onto the stack. * 
 *         -Adjusted PAREN_SEE/SEE output to show new non-colon words behavior.
 *         -Added MS.
 *         -Added COUNT.
 *         -Removed U. and Changed UDOT to U.
 *         -Renamed TELL to TYPE and added TELL as alias for TYPE.
 *         -Split CREATE into CREATE and (CREATE), the latter not calling WORD.
 *         -Added :NONAME (words will show up in WORDS output as {noname} for now).
 *         -Separated last (FIXUP) words in Library to separate entries.
 *         -Reversed .STACK output so it is in the same order as Forth Syntax Notation (ie rightmost is TOS).
 *         -Added ROLL.
 *         -Rewrote test.f EMPTY-STORAGE from
 *         
 *              SIZE 0 DO 0 OUTPUT I CELLS + ! LOOP \ fails!
 *              
 *          to
 *          
 *              OUTPUT SIZE CELLS ERASE             \ works!
 *              
 *         -Checked most WordSet Attributes (only FP is left).
 *         
 * 13092013-Added Dependencies to Library.
 *         -Removed duplicate words in Library.
 *         -Added memory type 3 support to all words involved (String Buffer).
 *         -Implemented Pictured Number Words.
 *         -Added <# # SIGN HOLD #S and #>.
 *         -The following examples are now working (note sign drops the numer but needs the original, so hence the DUP/DROP):
 *   
 *              : .DOLLAR <# # # 46 HOLD #S 36 HOLD #> TYPE ; 59998 0 .DOLLAR                 ->  $599.98
 *              //! USE S>D here to convert -59998 to a Double Cell Number
 *              : .DOLLAR <# DUP SIGN # # 46 HOLD #S 36 HOLD #> TYPE ; -59998 S>D .DOLLAR       ->  $599.98-    
 *              : .DOLLAR <# DUP # # 46 HOLD #S 36 HOLD DROP SIGN #> TYPE ; -59998 0 .DOLLAR  -> -$599.98
 *              
 *         -Removed PARENFIND.
 *         -Removed non functional R0 and S0 words.
 *         
 *         -Added more tests to test.f.
 *         -Corrected @* and @/ 
 *         -Corrected # #S and #> for Double Cell Numbers.
 *         -Added S>D
 *         
 * 14092013-Added Legacy Word Set.
 *         -Added .(
 *         -Added DIGIT, >NUMBER
 *         -Added M*, UM*, D2*, D2/, D+, D-, D* 
 *         -Added PARAM_STACK helpers (for Double-Cell Words).
 *         -Improved some unsigned number words with new helpers.
 *         -Added more test cases.
 *         -Addded FILL, MOVE (and made them byte sized).
 *         -Added FM/MOD and adjusted it to be Floored.
 *         -Added SM/REM
 *         -Added UM/MOD
 *         -Added C,
 *         -Formatted test cases.
 *         -Passed 587 of 681 tests (86%).
 *         -Split Words into partial classes per WordSet.
 *
 *         -Added ABORT
 *         -Added ABORT" (works in both COMPILE and INTERPRET mode, so Hybrid).
 *         -Updated Copyright in Words_* files.
 *         -Assigned WordSets to last words.
 *         -Added ENVIRONMENT?
 *         -Updated SEE for ABORT"
 *         
 *         -New ClickOnce Release (Build 7).
 *         
 * 15092013-Splitted Library into partial class per word-set.
 *         -Load String based words both from Words and Library Class.
 *         -Load String based words based on dependencies.
 *         -Started naming words accoring to ANSI X3.215-1994
 *         -Removed some duplicate words. *         
 *         -Corrected some typo's and ommisions in dependencies.
 *         
 *         -Added DUMP      (Tools word-set).
 *         -Completed TOOLS word-set.
 *         -Updated ENVIRONMENT?
 *         -Added BLANK     (String word-set).
 *         -Added CMOVE>    (String word-set).
 *         -Added EMIT?     (Facility-ext word-set).
 *         -Added KEY?      (Facility word-set).
 *         
 *         -Started on Double word-set:
 *         -Added 2CONSTANT
 *         -Added 2LITERAL 
 *         -Added 2VARIABLE
 *         -Added D.
 *         -Added D.R
 *         -Added D0<
 *         -Added D=
 *         -Added D<
 *         -Added D>S
 *         -Added DABS
 *         -Added DMAX
 *         -Added DMIN
 *         -Added DNEGATE
 *         -Added M* /
 *         -Added M+
 *         -Completed DOUBLE word-set.
 *         -Updated ENVIRONMENT?
 *         
 * 16092013-Added AT-XY        
 *         -Added Delegate/Event for Cursor Positioning.
 *         -Added TerminalWidth and TerminalHeight properties.
 *         -Completed FACILITY word-set.
 *         -Updated ENVIRONMENT?
 *         -Added TERM-HEIGHT and TERM-WIDTH.
 *         -Fixed some max-int issues in POP STACK.
 *         -Added equality test for BitConverter approach.
 *         -Fixed behavior of ?DO (when index and limit are equal the stack was not cleaned).
 *          This also fixes the testcases for 1 0 LSHIFT and 1 0 RSHIFT.
 *          Had to add a hidden word ?DOCLEAN.
 *
 *         -Added ACCEPT.
 *          Note: during ACCEPT no Console Editing is offered (so raw input).
 *          Note: in the main program a LF is appended to a CR when entered during ACCEPT.
 *         -Added SAVE-INPUT.
 *         -Added RESTORE-INPUT.
 *         -Enabled more tests (score now 616 pass, 63 still disabled/failing).
 *         -Added simple REFILL (just sets the flag if there is input in the queue).
 *         -Added EXPECT (calls ACCEPT).
 *         -Added SPAN.
 *         
 * 17092013-Added PAD.
 *         -Updated ENVIRONMENT? with /PAD size value.
 *         -Added SOURCE-ID (fixed to user input device for now).
 *         -Added PARSE.
 *         -Implemented MARKER.
 *         
 *          NOTE: Several Routines use the STRING_BUFFER and only a few know 
 *                when the input stored there is no longer neccesary (FIND for example)
 *                and can & will remove it accordingly. PARSE does not know. So 
 *                the memory occupied by STRING_BUFFER will grow over time.
 * 18092013-Fixed a nasty issue in ?DOCLEAN (used in ?DO and in LSHIFT/RSHIFT).
 *          It needs to be hidden but the code was flawed. Now appended HIDE ?DOCLEAN 
 *          to the only word calling it (will execute during compilation).
 *          This bug led to some test cases to fail.
 *         -Re-enabled FindHidden code.
 *         -Added a warning when hidden words are return.
 *         -Added a DecimalToBase that returns the String directly.
 *         -Made output of .S honor BASE.
 * 
 *         -New ClickOnce Release (Build 9).
 *         
 * 02012014-Note: The datatype used for F and DF is both C#'s Double.
 *         -Note: The datatype used for S is C#'s Single.
 *         -Note: The difference between S, F and DF seems to be:
 *            DF is a 64-Bits IEEE Double precision floating point
 *            S  is a 32-Bits IEEE Single precision floating point.
 *            F  is allowed to be any floating point type (so implementation dependend).
 *         -Added 2ROT
 *         -Added DU<
 *         -Corrected REPRESENT (removed F prefix).
 *         -Corrected F.
 *         -Added FABS
 *         -Added FACOS
 *         -Added FALOG
 *         -Added ASIN
 *         -Added ATAN
 *         -Added ATAN2
 *         -Added FCOS
 *         -Added FCOSH
 *         -Added FE.
 *         -Added FEXP
 *         -Added FEXPM1
 *         -Added FLN
 *         -Added FLNP1
 *         -Added FLOG
 *         -Added FS.
 *         -Added FSIN
 *         -Added FSINCOS
 *         -Added FSINH
 *         -Added FSQRT
 *         -Added FTAN
 *         -Added FTANH
 *         -Added F~
 *         -Added PRECISION
 *         -Added SET-PRECISION
 *         -Added Dummy FALIGN (Pointer manipulation not allowed)
 *         -Added Dummy FALIGNED (Pointer manipulation not allowed)
 *         -Added Dummy FDALIGN (Pointer manipulation not allowed)
 *         -Added Dummy FDALIGNED (Pointer manipulation not allowed)
 *         -Added DFLOAT+
 *         
 * 02012014-Added PI.
 *         -Added E.
 *      
 * 03012014-Added -TRAILING.
 *         -Added /STRING.
 *         -Added COMPARE.
 *         -Added SEARCH.
 *         -Added SLITERAL.
 *         -Added PEEK" (Shows the string at the top of teh stack).
 *         -Added warning about using S" in between [ ] (as it will define a new word during compilation of another).
 *         -Added $TEMP (Puts the %temp% variable into the string buffer and leaves the address/length).
 *          Can be used like ': TEMP [ $TEMP ] SLITERAL ;'.
 *         -Corrected errors in String retrieval from String Buffer (case should have break instead of return).
 *          Samples:
 *              8queens         compiles and seems to work.
 *              examples        works.
 *              exceptions      fails.
 *              fern            fails (graphical output).
 *              fibonacci       works.
 *              hanoi           works.
 *              hanoi2          works (disabled quite some code).
 *              regexp          fails to compile (due to >IN usage).
 *              spellnumber     works
 *              sudokusolver    works.
 *              eliza           fails to compile (ans forth, with many unknown words)
 *              life            ?
 *              sokoban         ?
 *              
 *          Missing from CORE (total of 133 words, 98% Implemented): 
 *              IN>
 *              SOURCE
 *              COUNT is implemented but useless as WORD/FIND do not use counted strings.
 *
 *          Differences from CORE:
 *              FIND & WORD do not use counted strings but normal Forth ones (pointer+length).
 *
 *          Missing from CORE EXT (total of 46 extension words):
 *              #TIB        (obsolete)
 *              C"
 *              COMPILE,
 *              CONVERT     (obsolete)
 *              QUERY       (obsolete)
 *              TIB         (obsolete)
 *              UNUSED
 *
 *          Missing from CODE EXT (total of 6 extension words):
 *              ;CODE
 *              AHEAD
 *              ASSEMBLER
 *              CODE
 *              CS-PICK
 *              CS-ROLL
 *              EDITOR
 *              STATE       (altered)
 *              [ELSE]
 *              [IF]
 *              [THEN]
 *
 *          Missing from BLOCK (total of ?? words):
 *              ?
 *              
 *          Missing from BLOCK EXT (total of ?? words):
 *              ?
 *              
 *          Missing from DOUBLE (total of 20 words):
 *              -
 *              
 *          Missing from DOUBLE EXT (total of 2 words):
 *              -
 *              
 *          Missing from EXCEPTION (total of 4 words):
 *              CATCH
 *              THROW
 *              ABORT       (altered)
 *              ABORT"      (altered)
 *              
 *          Missing from FACILITY (total of 3 extension words):
 *              -
 *              
 *          Missing from FACILITY EXT (total of 6 extension words):
 *              EKEY
 *              EKEY>CHAR
 *              EKEY?
 *              
 *          Missing from FILE (total of 20 words):
 *              (
 *              BIN
 *              CLOSE-FILE
 *              CREATE-FILE
 *              DELETE-FILE
 *              FILE-POSITION
 *              INCLUDE-FILE
 *              INCLUDED
 *              OPEN-FILE
 *              R/O
 *              R/W
 *              READ-FILE
 *              READ-LINE
 *              REPOSITION-FILE
 *              RESIZE-FILE
 *              S"
 *              SOURCE-ID
 *              W/O
 *              WRITE-FILE
 *              WRITE-LINE
 *              
 *          Missing from FILE EXT (total of 4 words):
 *              FILE-STATUS
 *              FLUSH-FILE
 *              REFILL
 *              RENAME-FILE
 *              
 *          Missing from FLOAT (total of 31 words):
 *              F!
 *              F@
 *              FALIGN
 *
 *          Missing from FLOAT EXT (total of 41 words):
 *              DF!
 *              DF@
 *              
 *              FACOSH      // Not in System.Math
 *              FASINH      // Not in System.Math
 *              FATANH      // Not in System.Math
 *              
 *              SF!         // Single Precision (ie float/Single)
 *              SF@         // Single Precision (ie float/Single)
 *              SFALIGN     // Single Precision (ie float/Single)
 *              SFALIGNED   // Single Precision (ie float/Single)
 *              SFLOAT+     // Single Precision (ie float/Single)
 *              SFLOATS     // Single Precision (ie float/Single)
 *
 *          Missing from LOCAL (total of 2 words):
 *              (LOCAL)
 *              TO
 *              
 *          Missing from LOCAL EXT (total 1 words):
 *              LOCALS|
 *          
 *          Missing from MEMORY (total of 3 words):
 *              ALLOCATE
 *              FREE
 *              RESIZE
 *              
 *          Missing from MEMORY EXT (total of 0 words):
 *              -
 * 
 *          Missing from TOOLS (total of 5 words):
 *              -
 *              
 *          Missing from TOOLS EXT (total of 13 words):
 *              ;CODE
 *              AHEAD
 *              ASSEMBLER
 *              CODE
 *              CS-PICK
 *              CS-ROLL
 *              EDITOR
 *              STATE
 *              [ELSE]
 *              [IF]
 *              [THEN]
 *              
 *          Missing from SEARCH (total of 9 words):
 *              DEFINITIONS
 *              FIND
 *              FORTH-WORDLIST
 *              GET-CURRENT
 *              GET-ORDER
 *              SEARCH-WORDLIST
 *              SET-CURRENT
 *              SET-ORDER
 *              WORDLIST
 *              
 *          Missing from SEARCH EXT (total of5 words):
 *              ALSO
 *              FORTH
 *              ONLY
 *              ORDER
 *              PREVIOUS
 *              
 *          Missing from STRING (total of 6 words):
 *              -
 *              
 *          Missing from STRING EXT (total of 0 words):
 *              -
 *              
 * -------- ----------------------------------------------
 *         -Added Examples from http://c2.com/cgi/wiki?ExampleForthCode (nice simple examples + output).
 *         -See http://theforthsource.com/guide.html (nice guide)
 *         -See http://www.forth.org/svfig/Win32Forth/DPANS94.txt (syntax).
 *         -See http://galileo.phys.virginia.edu/classes/551.jvn.fall01/primer.htm (guide)
 *         -See http://www.dst-corp.com/james/JonesForthInC/SPELLNUMBER.f.txt
 *         -See http://www.forth.com/starting-forth/sf11/sf11.html
 *         -See http://thebeez.home.xs4all.nl/ForthPrimer/Forth_primer.html
 *         -See http://www.rtr.myzen.co.uk/bb4wforth.zip
 *         -See http://www.jimbrooks.org/web/forth/forthInternals.php
 * -------- ----------------------------------------------
 * ANS94
 * 1)   Floating-Point words (FLOATING set)                      (12.6.1)
 * 2)   fileid (File Handle)
 * 3)   EXCEPTION set is separate….                              (9.6.1)
 * 4)   Standard error messages for ambiguous conditions.
 * 5)   Separate Control Stack ( C: ) ?
 * 6)   Endian                                                   (E.3.1)
 * 7)   Return Stack                                             (E.4.2   Stacks / 3.2.3.3)
 * 8)   Text-literal regions                                     (3.3.3.4)
 * 9)   Events for COLOR.
 * -------- ----------------------------------------------
 * 
 * //! TODO Implement THROW, CATCH, EXCEPTION-MARKER, ABORT.
 *          Not easy as ABORT depends on THROW and vice versa.
 *          
 * //! TODO Implement ACCEPT    (bb4wForth)
 * 
 * //! TODO Visualize RECURSE in SEE <word>. 
 *          So when the word contains a ref to itself.(D)
 *           
 * //! ERROR CR ERROR IF -1 ELSE 0 THEN INDEX + . ." Tested Passed" Fails.
 * //! ERROR 4294967295 U. (should give FFFFFFFF in HEX mode and itself in DECIMAL mode) 
 *           & -2147483648 U. Fail (HEX mode), compare to bb4wForth, .
 * -------- ----------------------------------------------
 */

#undef LOADLIB
#define LOADLIB

namespace SharpForth
{
    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Diagnostics;
    using System.Linq;
    using System.Reflection;
    using System.Text;
    using System.Linq.Expressions;
    using System.Runtime.InteropServices;
    using System.Windows.Forms;
    using System.IO;
    using System.Net;
    using System.Runtime.Serialization;
    using System.Threading;

    /// <summary>
    /// The SharpForth Interpreter. 
    /// 
    /// The Actual Interpreter Loop is located in the QUIT WORD that initializes the system a bit
    /// and continues to call the INTERPET WORD until the Forth.SHUTDOWN flag is set.
    /// 
    /// <remark> 
    /// ebp is used for the return stack,
    /// esp for the data stack,
    /// esi is the forth instruction pointer.
    /// </remark>
    /// </summary>
    public class Forth
    {
        #region Fields

        /// <summary>
        /// The Forth Word Dictionary. The moment DictionaryEntries are copied intt this list they are fully initialized.
        /// </summary>
        public static List<DictionaryEntry> Dictionary = new List<DictionaryEntry>();

        /// <summary>
        /// Accumulator.
        /// </summary>
        public static Int32 eax = 0;

        //! ESI is a combined value of two 16 words, lower part is index into the DictionaryEntry.Definition, upper part is the Index of DictionaryEntry.
        /// <summary>
        /// The virtual FORTH processor has an Instruction Pointer (IP) which points to Code Field Addresses. 
        /// IP is held in a register of the host processor. 
        /// The FORTH IP points to the pending CFA, not to the current CFA which is being executed (see Execution of Colon-Words). 
        /// This is the ESI/SI register on Intel x86 processors. 
        /// </summary>
        public static Int32 esi = 0;

        /// <summary>
        /// Due to the Lazy class usage, word references are resolved late/JIT (when copied in the correct order into the Dictionary List).
        /// Attributes like Dependencies and WordName are accessible without touching the wrapped DictionaryEntries.
        /// </summary>
        public static List<Lazy<DictionaryEntry>> LazyDictionary = new List<Lazy<DictionaryEntry>>();

        /// <summary>
        /// The Forth Parameter Stack.
        /// </summary>
        public static Stack<Int32> PARAM_STACK = new Stack<Int32>();

        /// <summary>
        /// The Forth Return Stack.
        /// </summary>
        public static Stack<Int32> RETURN_STACK = new Stack<Int32>();

        /// <summary>
        /// The Forth Floating Point Stack.
        /// </summary>
        public static Stack<Double> FPARAM_STACK = new Stack<Double>();

        /// <summary>
        /// Buffer for Parsing Words.
        /// </summary>
        public static List<Char> STRING_BUFFER = new List<Char>();

        /// <summary>
        /// Used as value for STATE.
        /// </summary>
        internal const Int32 COMPILE_MODE = 1;

        /// <summary>
        /// Name for Nameless Forth Words.
        /// </summary>
        internal const String NONAME = "{noname}";

        /// <summary>
        /// Forth Boolean value of False.
        /// </summary>
        internal const Int32 FORTH_FALSE = 0;

        /// <summary>
        /// Word FLAGS Bit - No Mask.
        /// </summary>
        internal const Int32 FORTH_NONE_MASK = 0x0000;

        /// <summary>
        /// WordFLAGS Bit - Word is Hidden (ie not listed with WORDS).
        /// </summary>
        internal const Int32 FORTH_HIDDEN_MASK = 0x0020;

        /// <summary>
        /// WordFLAGS Bit - Word will be executed even when in COMPILE_MODE.
        /// </summary>
        internal const Int32 FORTH_IMMED_MASK = 0x0080;

        /// <summary>
        /// Forth Boolean value of True.
        /// </summary>
        internal const Int32 FORTH_TRUE = -1;

        /// <summary>
        /// Used as value for STATE.
        /// </summary>
        internal const Int32 IMMEDIATE_MODE = 0;

        /// <summary>
        /// The Version Number.
        /// </summary>
        internal static readonly Version SharpForthVersion;

        /// <summary>
        /// Marks a pointer into Definitions List.
        /// </summary>
        internal const Int32 MEM_DEF = 0 << 30;

        /// <summary>
        /// Marks a Pointer into the RETURN_STACK.
        /// </summary>
        internal const Int32 MEM_RSP = 1 << 30;

        /// <summary>
        /// Marks a Pointer ito PARAM_STACK.
        /// </summary>
        internal const Int32 MEM_PRM = 2 << 30;

        /// <summary>
        /// Marks a pointer into STRING_BUFFER.
        /// </summary>
        internal const Int32 MEM_WRD = 3 << 30;

        /// <summary>
        /// Used to store tha DICTIONARY/DEFINITION address of BASE Storage.
        /// </summary>
        internal static Int32 BASE_ADDRESS = -1;

        /// <summary>
        /// Address of last built-in address of this Forth.
        /// 
        /// It will be set at the end of the constructor and 
        /// finalized after reading the Static Forth Library (if any).
        /// </summary>
        internal static Int32 BUILT_IN = 0;

        /// <summary>
        /// Stores pointer to next char retrieved by KEY.
        /// </summary>
        internal static Int32 CURRKEY = 0; //! TODO

        /// <summary>
        /// Top of the RETURN_STACK.
        /// </summary>
        internal static Int32 RZ = 0;

        /// <summary>
        /// Top of the PARAM_STACK.
        /// </summary>
        internal static Int32 SZ = 0;

        /// <summary>
        /// Address Inside DICTIONARY of the Definition containg DP.
        /// </summary>
        private static Int32 DP_ADDRESS = -1;

        /// <summary>
        /// The Saved Value of DP (needed as long as DP_ADDRESS is not defined).
        /// </summary>
        private static Int32 DP_VALUE = 0;

        /// <summary>
        /// Address Inside DICTIONARY of the Definition containing LATEST.
        /// </summary>
        private static Int32 LATEST_ADDRESS = -1;

        /// <summary>
        /// The Saved Value of LATEST (needed as long as LATEST_ADDRESS is not defined).
        /// </summary>
        private static Int32 LATEST_VALUE = 0;

        /// <summary>
        /// Address Inside DICTIONARY of the Definition containing SPAN.
        /// </summary>
        private static Int32 SPAN_ADDRESS = -1;

        /// <summary>
        /// SPAN, the length of String received by EXPECT.
        /// </summary>
        private static Int32 SPAN_VALUE = 0;

        /// <summary>
        /// Address containing STATE.
        /// </summary>
        private static Int32 STATE_ADDRESS = -1;

        /// <summary>
        /// The Saved Value of TRACE (needed as long as TRACE_ADDRESS is not defined).
        /// </summary>
        private static Boolean TRACE_VALUE = false;

        /// <summary>
        /// Address containing TRACE.
        /// </summary>
        private static Int32 TRACE_ADDRESS = -1;

        /// <summary>
        /// The Saved Value of DP (needed as long as DP_ADDRESS is not defined).
        /// </summary>
        private static Int32 STATE_VALUE = IMMEDIATE_MODE;

        /// <summary>
        /// For use with ELAPSED.
        /// </summary>
        internal static Int64 START_TICKS = DateTime.Now.Ticks;

        /// <summary>
        /// The working area for PICTURED numbers
        /// </summary>
        internal static String PICTURE = String.Empty;

        /// <summary>
        /// The list of loaded (built-in) Forth Words.
        /// </summary>
        internal static List<String> LoadedWords = new List<String>();

        /// <summary>
        /// The number of runs we take on various sources of Forh Words:
        /// 
        /// 1) Words delegates.
        /// 2) Words strings.
        /// 3) Library strings.
        /// </summary>
        internal static Int32 globalpass = 0;

        internal const Int32 PAD_SIZE = 1024;

        internal static Boolean FindHidden = false;

        internal static Int32 Precision = 6;

        #endregion Fields

        #region Constructors

        /// <summary>
        /// Constructor, initializes the Forth Interpreter and fills the Dictionary with built-in Words.
        /// </summary>
        static Forth()
        {
            Forth.Shutdown = false;

            if (System.Deployment.Application.ApplicationDeployment.IsNetworkDeployed)
            {
                SharpForthVersion = System.Deployment.Application.ApplicationDeployment.CurrentDeployment.CurrentVersion;

                Debug.Print("ClickOnce Version: v{0}", SharpForthVersion);
            }
            else
            {
                SharpForthVersion = typeof(Forth).Assembly.GetName().Version;

                Debug.Print("Assembly Version: v{0}", SharpForthVersion);
            }
            Debug.Print("Product Version: v{0}", Application.ProductVersion);

            TerminalWidth = 80;
            TerminalHeight = 40;

            InitForth();

            AddBuiltInWords();

            BUILT_IN = I2A(Dictionary.Count - 1);

            LibraryNdx = 0;
        }

        #endregion Constructors

        #region Delegates

        /// <summary>
        /// SharpForth's connection to the Front-End.
        /// </summary>
        public delegate Boolean KeyAvailableDelegate();

        /// <summary>
        /// SharpForth's connection to the Front-End.
        /// </summary>
        public delegate void GetKeyDelegate(Boolean buffer = false);

        /// <summary>
        /// SharpForth's connection to the Front-End.
        /// </summary>
        public delegate void GotoXYDelegate(Int32 x, Int32 y);

        /// <summary>
        /// SharpForth's connection to the Front-End.
        /// </summary>
        public delegate void OutputDelegate(String txt, Boolean line = false);

        #endregion Delegates

        #region Events

        /// <summary>
        /// SharpForth's connection to the Front-End.
        /// </summary>
        public static event KeyAvailableDelegate OnKeyAvailableEvent;

        /// <summary>
        /// SharpForth's connection to the Front-End.
        /// </summary>
        public static event GetKeyDelegate OnGetKeyEvent;

        /// <summary>
        /// SharpForth's connection to the Front-End.
        /// </summary>
        public static event GotoXYDelegate OnGotoXYEvent;

        /// <summary>
        /// SharpForth's connection to the Front-End.
        /// </summary>
        public static event OutputDelegate OnOutputEvent;

        #endregion Events

        #region Properties

        /// <summary>
        /// The current base for printing and reading numbers.
        /// 
        /// This value can only be returned if the word is fully defined (so thats the reason for baseadr).
        /// 
        /// Until reachable BASE will return the default value of 10 (Decimal).
        /// 
        /// It's quite a tweak but the definition of the word needs teh value to be stored on an address.
        /// The code mimics a Built-In Forth Variable. 
        /// 
        /// It's currently the only Variable you can set. 
        /// 
        /// Others Variables (BUILT-IN) just emit their computed value (LATEST and DP are coded similarly).
        /// </summary>
        internal static Int32 BASE
        {
            get
            {
                return (BASE_ADDRESS == -1) ? 10 : Dictionary[BASE_ADDRESS >> 16].Definition[(BASE_ADDRESS % 65536) >> 2];
            }
        }

        /// <summary>
        /// DP.
        /// </summary>
        internal static Int32 DP
        {
            get
            {
                return (DP_ADDRESS == -1) ? DP_VALUE : Dictionary[DP_ADDRESS >> 16].Definition[(DP_ADDRESS % 65536) >> 2];
            }
            set
            {
                DP_VALUE = value;

                if (DP_ADDRESS != -1)
                {
                    Dictionary[DP_ADDRESS >> 16].Definition[(DP_ADDRESS % 65536) >> 2] = DP_VALUE;
                }
            }
        }

        /// <summary>
        /// LATEST.
        /// </summary>
        internal static Int32 LATEST
        {
            get
            {
                return (LATEST_ADDRESS == -1) ? LATEST_VALUE : Dictionary[LATEST_ADDRESS >> 16].Definition[(LATEST_ADDRESS % 65536) >> 2];
            }
            set
            {
                LATEST_VALUE = value;

                if (LATEST_ADDRESS != -1)
                {
                    Dictionary[LATEST_ADDRESS >> 16].Definition[(LATEST_ADDRESS % 65536) >> 2] = LATEST_VALUE;
                }
            }
        }

        /// <summary>
        /// SPAN.
        /// </summary>
        internal static Int32 SPAN
        {
            get
            {
                return (SPAN_ADDRESS == -1) ? SPAN_VALUE : Dictionary[SPAN_ADDRESS >> 16].Definition[(SPAN_ADDRESS % 65536) >> 2];
            }
            set
            {
                SPAN_VALUE = value;

                if (SPAN_ADDRESS != -1)
                {
                    Dictionary[SPAN_ADDRESS >> 16].Definition[(SPAN_ADDRESS % 65536) >> 2] = SPAN_VALUE;
                }
            }
        }

        /// <summary>
        /// Toggles the TRACE Flag.
        /// </summary>
        internal static Boolean TRACE
        {
            get
            {
                return (TRACE_ADDRESS == -1) ? TRACE_VALUE : Dictionary[TRACE_ADDRESS >> 16].Definition[(TRACE_ADDRESS % 65536) >> 2] != Forth.FORTH_FALSE;
            }
            set
            {
                TRACE_VALUE = value;

                if (TRACE_ADDRESS != -1)
                {
                    Dictionary[TRACE_ADDRESS >> 16].Definition[(TRACE_ADDRESS % 65536) >> 2] = TRACE_VALUE ? Forth.FORTH_TRUE : Forth.FORTH_FALSE;
                }
            }
        }

        /// <summary>
        /// Terminal Width.
        /// </summary>
        [DefaultValue(80)]
        public static Int32 TerminalWidth
        {
            get;
            set;
        }

        /// <summary>
        /// Terminal Height.
        /// </summary>
        [DefaultValue(40)]
        public static Int32 TerminalHeight
        {
            get;
            set;
        }

        /// <summary>
        /// Init Forth Compiler.
        /// </summary>
        public static void InitForth()
        {
            Forth.RETURN_STACK.Clear();
            Forth.PARAM_STACK.Clear();
            Forth.STRING_BUFFER.Clear();
            Forth.FPARAM_STACK.Clear();

            Forth.START_TICKS = DateTime.Now.Ticks;
        }

        /// <summary>
        /// Signals the need to shut the interpreter down.
        /// </summary>
        public static Boolean Shutdown
        {
            get;
            set;
        }

        /// <summary>
        /// Is the interpreter executing code (0) or compiling a word (non-zero)?
        /// </summary>
        public static Int32 STATE
        {
            get
            {
                return (STATE_ADDRESS == -1) ? STATE_VALUE : Dictionary[STATE_ADDRESS >> 16].Definition[(STATE_ADDRESS % 65536) >> 2];
            }
            set
            {
                STATE_VALUE = value;

                if (STATE_VALUE != -1)
                {
                    Dictionary[STATE_ADDRESS >> 16].Definition[(STATE_ADDRESS % 65536) >> 2] = STATE_VALUE;
                }
            }
        }

        #endregion Properties

        #region Methods

        /// <summary>
        /// Dump Dictionary.
        /// </summary>
        public static void DUMP_DICTIONARY()
        {
            Debug.Print("[DICTIONARY]");
            foreach (DictionaryEntry entry in Dictionary.ToArray())
            {
                Debug.Print("{0}", entry.ToString());
            }
            Debug.Print(String.Empty);
        }

        /// <summary>
        /// Dump Dictionary Entry (Recursively).
        /// </summary>
        /// <param name="entry">The DictionaryEntry to Dump</param>
        /// <param name="recurse">If true the words are dissassembled recursively</param>
        public static void DUMP_DICTIONARY_ENTRY(DictionaryEntry entry, Boolean recurse = false)
        {
            Debug.Print("[DICTIONARY_ENTRY]");
            Debug.Print("Index=  0x{0}", Dictionary.IndexOf(entry).ToString("X4"));
            Debug.Print("Address=0x{0}", Locate(entry.Name).ToString("X8"));
            Debug.Print("Name=   {0}", entry.Name);

            Debug.Print("C#=     {0}", entry.IsSharpCode);
            Debug.Print("Forth=  {0}", entry.IsForthCode);

            if (entry.IsForthCode)
            {
                Debug.Print("Size=   {0}", entry.Definition.Count);
            }

            Debug.Print(String.Empty);

            Debug.Indent();
            for (Int32 i = 0; i < entry.Definition.Count; i++)
            {
                Int32 ndx = entry.Definition[i] >> 16;

                //! -------------------------
                //! Take Special Care of LIT!
                //! -------------------------

                if (recurse)
                {
                    DUMP_DICTIONARY_ENTRY(Dictionary[ndx]);
                    if (Dictionary[ndx].Name.Equals("LIT"))
                    {
                        i++;
                        Debug.Print("[LITERAL_VALUE]");
                        Debug.Print("Value=  {0} (0x{1})", entry.Definition[i], entry.Definition[i].ToString("X8"));
                        Debug.Print(String.Empty);
                    }
                }
                else
                {
                    Debug.Print(Dictionary[ndx].Name);
                    if (Dictionary[ndx].Name.Equals("LIT"))
                    {
                        i++;
                        Debug.Print(entry.Definition[i].ToString("X8"), true);
                    }
                }
            }
            Debug.Unindent();
        }

        /// <summary>
        /// Dump Parameter Stack.
        /// </summary>
        public static void DUMP_PARAM_STACK()
        {
            Debug.Print("[DATA]");
            foreach (Int32 data in PARAM_STACK.ToArray().Reverse())
            {
                Debug.Print("{0}", data);
            }
            Debug.Print(String.Empty);
        }

        /// <summary>
        /// Dump Floating Point Stack.
        /// </summary>
        public static void DUMP_FPARAM_STACK()
        {
            Debug.Print("[DATA]");
            foreach (Int32 data in FPARAM_STACK.ToArray().Reverse())
            {
                Debug.Print("{0}", data);
            }
            Debug.Print(String.Empty);
        }

        /// <summary>
        /// Dump Return Stack.
        /// </summary>
        public static void DUMP_RETURN_STACK()
        {
            Debug.Print("[RETURN_STACK]");
            foreach (Int32 data in RETURN_STACK.ToArray().Reverse())
            {
                Debug.Print("{0}", data);
            }
            Debug.Print(String.Empty);
        }

        /// <summary>
        /// Dump Word Buffer.
        /// </summary>
        public static void DUMP_WORD_BUFFER()
        {
            Debug.Write("[WORD_BUFFER]");
            for (Int32 i = 0; i < STRING_BUFFER.Count; i++)
            {
                if (i % 40 == 0)
                {
                    Debug.Print(String.Empty);
                }
                Debug.Write(STRING_BUFFER[i]);
            }
            Debug.Print(String.Empty);
        }

        /// <summary>
        /// Forgets all words defined (and including) after the marker.
        /// </summary>
        /// <param name="ndx">The word Dictionary index</param>
        public static void ForgetMarker(Int32 ndx)
        {
            Int32 cnt = 0;

            Int32 noname = 0;
            Int32 hidden = 0;

            if (ndx != -1)
            {
                while (Forth.Dictionary.Count > ndx)
                {
                    if (Forth.Dictionary.Count - 1 <= Forth.A2I(Forth.BUILT_IN))
                    {
                        if (ndx != 0)
                        {
                            Forth.DoOutput(Forth.ErrorMarker + "Cannot forget BUILT-IN Words.", true);
                        }
                        break;
                    }

                    if ((Forth.Dictionary.Last().Flags & Forth.FORTH_HIDDEN_MASK) == Forth.FORTH_HIDDEN_MASK)
                    {
                        hidden++;
                    }
                    if (Forth.Dictionary.Last().Name.Equals(Forth.NONAME))
                    {
                        noname++;
                    }
                    Forth.Dictionary.Remove(Forth.Dictionary.Last());
                    cnt++;
                }
            }
            else
            {
                Forth.DoOutput(Forth.ErrorMarker + "Cannot forget undefined Words.", true);
            }

            if (hidden != 0 || noname != 0)
            {
                Forth.DoOutput("Forgot {0} Word(s) ({1} hidden, {2} nameless)", cnt, hidden, noname);
            }
            else
            {
                Forth.DoOutput("Forgot {0} Word(s)", cnt, hidden, noname);
            }
        }

        /// <summary>
        /// Get the Depends Attribute Values of an Field.
        /// </summary>
        /// <param name="fi">The FieldInfo of the Field</param>
        /// <returns>The Depends Attribute Values</returns>
        internal static List<String> GetDependencies(FieldInfo fi)
        {
            List<String> Result = new List<String>();

            Object[] attrs = fi.GetCustomAttributes(typeof(DependsAttribute), false);
            if (attrs != null)
            {
                foreach (Attribute attr in attrs)
                {
                    Result.Add(((DependsAttribute)attr).Word);
                }
            }

            return Result;
        }

        /// <summary>
        /// Get the WordName Attribute Value of an Field.
        /// </summary>
        /// <param name="fi">The FieldInfo of the Field</param>
        /// <returns>The WordName Attribute Value</returns>
        internal static String GetWordName(FieldInfo fi)
        {
            Object[] attrs = fi.GetCustomAttributes(typeof(WordNameAttribute), false);

            if (attrs != null && attrs.Length > 0)
            {
                return ((WordNameAttribute)attrs[0]).Word;
            }

            return fi.Name;
        }

        /// <summary>
        /// Get the WordSet Attribute Value of an Field.
        /// </summary>
        /// <param name="fi">The FieldInfo of the Field</param>
        /// <returns>The WordSet Attribute Value</returns>
        internal static WordSets GetWordSet(FieldInfo fi)
        {
            Object[] attrs = fi.GetCustomAttributes(typeof(WordSetAttribute), false);

            if (attrs != null && attrs.Length > 0)
            {
                return ((WordSetAttribute)attrs[0]).WordSet;
            }

            return WordSets.NONE;
        }

        /// <summary>
        /// Get the Description Attribute Value of an Field.
        /// </summary>
        /// <param name="fi">The FieldInfo of the Field</param>
        /// <returns>The Description Attribute Value</returns>
        internal static String GetDescription(FieldInfo fi)
        {
            Object[] attrs = fi.GetCustomAttributes(typeof(DescriptionAttribute), false);

            if (attrs != null && attrs.Length > 0)
            {
                return ((DescriptionAttribute)attrs[0]).Description;
            }

            return fi.Name;
        }

        /// <summary>
        /// Usage: new AnEnum().GetDescriptions
        /// </summary>
        /// <param name="e"></param>
        /// <param name="value"></param>
        /// <returns></returns>
        internal static String GetDescription(Type e, Enum value)
        {
            FieldInfo field = e.GetField(value.ToString());
            if (field != null)
            {
                DescriptionAttribute attr = Attribute.GetCustomAttribute(field, typeof(DescriptionAttribute)) as DescriptionAttribute;
                if (attr != null)
                {
                    return attr.Description;
                }
            }

            return value.ToString();
        }

        /// <summary>
        /// Get the Description Attribute Value of an Field.
        /// </summary>
        /// <param name="fi">The FieldInfo of the Field</param>
        /// <returns>The Description Attribute Value</returns>
        internal static String GetSyntax(FieldInfo fi)
        {
            Object[] attrs = fi.GetCustomAttributes(typeof(SyntaxAttribute), false);

            if (attrs != null && attrs.Length > 0)
                return ((SyntaxAttribute)attrs[0]).Syntax;

            return GetWordName(fi);
        }

        /// <summary>
        /// This does some magic, it returns the name of a property so it is no longer 
        /// a problematic string value problematic when refactoring.
        /// 
        /// Usage: string pricePropertyName = ObjectUtils.GetMemberName&lt;IProduct&gt;(p =&gt; p.Price);
        /// </summary>
        /// <typeparam name="T">The type to which the property belongs</typeparam>
        /// <param name="action">-</param>
        /// <returns>The property name</returns>

        public static string GetMemberName<T>(Expression<Func<T, object>> action)
        {
            var lambda = (LambdaExpression)action;

            if (lambda.Body is UnaryExpression)
            {
                var unary = (UnaryExpression)lambda.Body;
                var operand = unary.Operand;

                if (ExpressionType.MemberAccess == operand.NodeType)
                {
                    var memberExpr = (MemberExpression)operand;

                    return memberExpr.Member.Name;
                }
                else if (ExpressionType.Call == operand.NodeType)
                {
                    var methodExpr = (MethodCallExpression)operand;

                    return methodExpr.Method.Name;
                }
            }
            else
            {
                var memberExpr = (MemberExpression)lambda.Body;

                return memberExpr.Member.Name;
            }

            throw new InvalidOperationException();
        }

        /// <summary>
        /// Locate Word in Dictionary by Name.
        /// </summary>
        /// <param name="Name">The Name of the Word to Locate</param>
        /// <returns>The Pseudo Address of the Word or -1</returns>
        public static Int32 Locate(String Name)
        {
            if (String.IsNullOrEmpty(Name))
            {
                return -1;
            }

            foreach (DictionaryEntry entry in Dictionary.Reverse<DictionaryEntry>())
            {
                if (entry.Name.Equals(Name, StringComparison.OrdinalIgnoreCase))
                {
                    if (FindHidden || ((entry.Flags & Forth.FORTH_HIDDEN_MASK) != Forth.FORTH_HIDDEN_MASK))
                    {
                        if ((entry.Flags & Forth.FORTH_HIDDEN_MASK) == Forth.FORTH_HIDDEN_MASK)
                        {
                            Debug.Print("Returing Hidden Word '{0}'", entry.Name);
                        }

                        return Dictionary.IndexOf(entry) << 16;
                    }
                }
            }

            Int32 dummy;
            if (Forth.BaseToDecimal(Name, Forth.BASE, out dummy) != 0)
            {
                DoOutput(String.Format(ErrorMarker + "'{0}' is undefined.", Name), true);
            }

            return -1;
        }

        /// <summary>
        /// Locate Word in Dictionary by Name.
        /// </summary>
        /// <param name="name">The Name of the Word to Locate</param>
        /// <returns>The Index of the Word in the Dictionary or -1</returns>
        public static Int32 LocateI(String name)
        {
            Int32 adr = Locate(name);

            if (adr != -1)
            {
                return A2I(adr);
            }
            else
            {
                return adr;
            }
        }

        /// <summary>
        /// NEXT does not function properly yet from withing Execute().
        /// 
        /// All three registers: esi, aex and pc are still unused!
        /// 
        ///! 517
        /// </summary>
        public static void NEXT()
        {
            //! Safeguard so we can use NEXT without causing Exceptions.
            //if (esi != 0)
            //{
            //! Simulate byte addressing in the lower word by dividing by 4.

            //! LODSD
            //if ((esi % 65536) >> 2 < Dictionary[esi >> 16].Definition.Count)
            //{
            //    eax = Dictionary[esi >> 16].Definition[(esi % 65536) >> 2];
            //    esi += 4;
            //}

            ////! JMP [AEX]
            ////! Execute eax...
            //pc = Dictionary[eax >> 16].Definition[(eax % 65536) >> 2];

            //EXECUTE();
            //}
        }

        internal static void AddForthWord(String Name, Int32 Flags)
        {
            DictionaryEntry de = new DictionaryEntry(Name, Flags);

            Forth.Dictionary.Add(de);
        }

        //internal static Int32 ReverseBytes(Int32 value)
        //{
        //    UInt32 val = (UInt32)value;
        //    val = (val & 0x000000FFU) << 24 | (val & 0x0000FF00U) << 8 |
        //            (val & 0x00FF0000U) >> 8 | (val & 0xFF000000U) >> 24;
        //    return (Int32)val;
        //}

        /// <summary>
        /// See http://www.codeproject.com/Articles/10507/Conversion-of-Decimal-to-any-Base-Binary-Octal-or
        /// 
        /// Base 36 (10+26) is max.
        /// 
        /// Mimic behavior of bbwForth (return number of unparsed characters and multiply result before with nBase!
        /// 
        /// So:
        /// 
        /// 12A7 returns 2 120
        /// 1A7  returns 2  10
        /// 12A  returns 1 120
        /// 129  returns 0 129
        /// </summary>
        /// <param name="input"></param>
        /// <param name="nBase"></param>
        /// <param name="result"></param>
        /// <returns>0 if the conversion was a success else the number of unconverted characters</returns>
        internal static Int32 BaseToDecimal(String input, Int32 nBase, out Int32 result)
        {
            result = 0;

            string characters = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
            if (nBase < 2 || nBase > characters.Length)
            {
                return input.Length;
            }

            bool negative = false;
            if (input.StartsWith("-"))
            {
                negative = true;
                input = input.Substring(1);
            }
            for (int i = 0; i < input.Length; i++)
            {
                int value = characters.IndexOf(input[i]);

                //! Mimic behavior of bbwForth (return number of unparsed characters and multiply result before with nBase!
                result *= nBase;

                if (value >= nBase || value < 0)
                {
                    //! Mimic behavior of bbwForth (return number of unparsed characters and multiply result before with nBase!
                    return input.Length - i;
                }
                result += value; //* (int)Math.Pow(nBase, input.Length - i - 1);
            }
            if (negative)
            {
                result *= -1;
            }

            return 0;
        }

        /// <summary>
        /// See http://www.codeproject.com/Articles/10507/Conversion-of-Decimal-to-any-Base-Binary-Octal-or
        /// 
        /// Base 36 (10+26) is max.
        /// </summary>
        /// <param name="input"></param>
        /// <param name="nBase"></param>
        /// <param name="result"></param>
        /// <returns>True if the conversion was a success</returns>
        internal static Boolean DecimalToBase(Int32 input, Int32 nBase, out String result)
        {
            Int64 input64 = input;

            result = String.Empty;

            string characters = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
            if (nBase < 2 || nBase > characters.Length)
            {
                // DoOutput(new ArgumentOutOfRangeException("BASE", nBase, "Range: 2.." + characters.Length).Message);
                return false;
            }

            if (input == 0)
            {
                result = "0";
            }
            else
            {
                bool negative = false;
                if (input64 < 0)
                {
                    negative = true;
                    input64 *= -1;
                }
                StringBuilder sb = new StringBuilder();
                while (input64 != 0)
                {
                    sb.Insert(0, (characters[(Int32)(input64 % (Int64)nBase)]));
                    input64 /= nBase;
                }
                if (negative) //&& nBase != 16
                {
                    sb.Insert(0, "-");
                }

                result = sb.ToString();
            }

            return true;
        }

        /// <summary>
        /// Assumes the conversion will work.
        /// </summary>
        /// <param name="input"></param>
        /// <param name="nBase"></param>
        /// <returns></returns>
        internal static String DecimalToBase(Int32 input, Int32 nBase)
        {
            String result = String.Empty;

            DecimalToBase(input, nBase, out result);

            return result;
        }

        /// <summary>
        /// See http://www.strw.leidenuniv.nl/docs/intel/ref/cnst_c.htm
        /// </summary>
        /// <param name="number"></param>
        /// <param name="Base"></param>
        /// <returns></returns>
        public static String NumericPrefix(String number, Int32 Base)
        {
            switch (Base)
            {
                //! 0[bB][01]*
                case 2:
                    return number.Insert(number.IndexOf('-') == 0 ? 1 : 0, "0b");

                //! 0[0-7]*
                case 8:
                    //if (number.StartsWith("0") || number.StartsWith("-0"))
                    //{
                    //    return number;
                    //}
                    //else
                    //{
                    return number.Insert(number.IndexOf('-') == 0 ? 1 : 0, "0");
                //}

                //! [1-9][0-9]*
                case 10:
                    return number;

                //! 0[xX][0-9a-fA-F]*
                case 16:
                    return number.Insert(number.IndexOf('-') == 0 ? 1 : 0, "0x");

                default:
                    return number;
            }
        }

        /// <summary>
        /// Positions the cursor at a Terminal Column and Row.
        /// </summary>
        /// <param name="x">Column</param>
        /// <param name="y">Row</param>
        internal static void DoOnGotoXY(Int32 x, Int32 y)
        {
            if (OnGotoXYEvent != null)
            {
                OnGotoXYEvent(x, y);
            }
            //else
            //{
            //Debug.Print("OnGotoXY({0},{1})", x, y);
            //}
        }

        /// <summary>
        /// Emit a String to the Console/Application.
        /// </summary>
        /// <param name="txt">The Text to Emit</param>
        /// <param name="line">If true a crlf should be added</param>
        internal static void DoOutput(String txt, Boolean line = false)
        {
            if (OnOutputEvent != null)
            {
                OnOutputEvent(txt, line);
            }
            //else
            //{
            //Debug.Print("OnDoOutput('{0}',{1}", txt, line);
            //}
        }

        /// <summary>
        /// Emit a String to the Console/Application.
        /// </summary>
        /// <param name="format">The String.Format alike Format.</param>
        /// <param name="args">The Arguments for the Format String.</param>
        internal static void DoOutput(String format, params Object[] args)
        {
            OnOutputEvent(String.Format(format, args));
        }

        internal static String FetchWord(Int32 start, Int32 length, Boolean remove = false)
        {
            String word = String.Empty;

            Int32 mt = Forth.A2M(start);

            if (start < I2A(1))
            {
                for (Int32 i = 0; i < length; i++)
                {
                    word += STRING_BUFFER[(start & Forth.MTM) + i];
                }
            }
            else
            {
                for (Int32 i = 0; i < length; i++)
                {
                    switch (mt)
                    {
                        case Forth.MEM_DEF:
                            word += (Char)new Int32ByteUnion(Forth.Dictionary[Forth.A2I(start)].Definition[Forth.A2D(start)])[start % 4];
                            break;
                        case Forth.MEM_RSP:
                            Forth.DoOutput("MemoryType 1 Not Implemented");
                            break;
                        case Forth.MEM_PRM:
                            Forth.DoOutput("MemoryType 2 Not Implemented");
                            break;
                        case Forth.MEM_WRD:
                            word += STRING_BUFFER[Forth.A2A(start)];
                            break;
                    }

                    start++;
                }
            }

            if (start < I2A(1) && remove)
            {
                //! Cannot Remove Strings inside the buffer
                if (remove)
                {
                    if (Forth.A2A(start) + length == STRING_BUFFER.Count)
                    {
                        for (Int32 i = 0; i < word.Length; i++)
                        {
                            STRING_BUFFER.RemoveAt(STRING_BUFFER.Count - 1);
                        }
                    }
                    else
                    {
                        if (start != 0 && length != 0)
                        {
                            DoOutput(ErrorMarker + "Cannot remove String inside the Word Buffer.");
                        }
                    }
                }
            }

            return word;
        }

        internal static void Init()
        {
            if (Forth.Locate("QUIT") != -1)
            {
                Forth.esi = +4;

                Words.QUIT.Value.Invoke();
            }
        }

        internal static Int32 MTM = 0x3FFFFFFF;
        internal static UInt32 NOTMTM = 0xC0000000;

        /// <summary>
        /// Convert Dictionary Index into Pseudo Address.
        /// </summary>
        /// <param name="ndx"></param>
        /// <returns></returns>
        internal static Int32 I2A(Int32 ndx)
        {
            return (ndx << 16) & MTM;
        }

        /// <summary>
        /// Convert Pseudo Address into Dictionary Index.
        /// </summary>
        /// <param name="adr"></param>
        /// <returns></returns>
        internal static Int32 A2I(Int32 adr)
        {
            return (adr & MTM) >> 16;
        }

        /// <summary>
        /// Strips Memory Type.
        /// </summary>
        /// <param name="adr"></param>
        /// <returns></returns>
        internal static Int32 A2A(Int32 adr)
        {
            return (adr & MTM);
        }

        /// <summary>
        ///  Convert Pseudo Address into a Memory Type.
        /// </summary>
        /// <param name="adr"></param>
        /// <returns>Memory Type</returns>
        internal static Int32 A2M(Int32 adr)
        {
            return adr & (Int32)NOTMTM;
        }

        /// <summary>
        ///  Convert Memory Type into Pseudo Address.
        /// </summary>
        /// <param name="adr"></param>
        /// <param name="mt">Memory Type (0..3)</param>
        /// <returns></returns>
        internal static Int32 M2A(Int32 adr, Int32 mt)
        {
            return adr % (mt << 30);
        }

        /// <summary>
        /// Convert Pseudo Address into Definition Index.
        /// 
        /// Fetch the lower 16 bits and mask the upper 2 for Int32 size CELLS.
        /// </summary>
        /// <param name="adr"></param>
        /// <returns></returns>
        internal static Int32 A2D(Int32 adr)
        {
            return (adr % 65536) >> 2;
        }

        /// <summary>
        /// Pop a Value from the Parameter Stack.
        /// </summary>
        /// <returns></returns>
        internal static Int32 POP_P_STACK()
        {
            if (PARAM_STACK.Count != 0)
            {
                return PARAM_STACK.Pop();
            }
            else
            {
                DoOutput(ErrorMarker + "Cannot Pop from Empty Parameter Stack.", true);
            }

            //! TODO Exception

            return -1;
        }

        /// <summary>
        /// Pop a Value from the Parameter Stack.
        /// </summary>
        /// <returns></returns>
        internal static UInt32 POP_P_STACK_2U()
        {
            if (PARAM_STACK.Count != 0)
            {
                return (UInt32)PARAM_STACK.Pop();
            }
            else
            {
                DoOutput(ErrorMarker + "Cannot Pop from Empty Parameter Stack.", true);
            }

            //! TODO Exception

            return 0xFFFFFFFF;
        }

        /// <summary>
        /// Pop a Value from the Return Stack.
        /// 
        /// //! 706
        /// </summary>
        /// <returns></returns>
        internal static Int32 POP_R_STACK()
        {
            if (RETURN_STACK.Count != 0)
            {
                return RETURN_STACK.Pop();
            }
            else
            {
                DoOutput(ErrorMarker + "Cannot Pop from Empty Return Stack.", true);
            }
            //! TODO Exception
            return -1;
        }

        /// <summary>
        /// Pop a Value from the Floating Point Stack.
        /// </summary>
        /// <returns></returns>
        internal static Double POP_F_STACK()
        {
            if (FPARAM_STACK.Count != 0)
            {
                return FPARAM_STACK.Pop();
            }
            else
            {
                DoOutput(ErrorMarker + "Cannot Pop from Empty Floating Point Stack.", true);
            }

            //! TODO Exception

            return Double.NaN;
        }
        /// <summary>
        /// Pop a Value from the Return Stack.
        /// 
        /// //! 706
        /// </summary>
        /// <param name="reg1"></param>
        /// <param name="reg2"></param>
        internal static void POP_2_R_STACK(out Int32 reg1, out Int32 reg2)
        {
            reg1 = POP_R_STACK();
            reg2 = POP_R_STACK();
        }

        internal static Int64 POP_P_STACK_2D()
        {
#pragma warning disable 0675
            Int32 msw = Forth.POP_P_STACK();
            Int32 lsw = Forth.POP_P_STACK();

            Int64 d = (((Int64)(UInt32)msw) << 32) | (Int64)(UInt32)lsw; //MSW, LSW

            if (d != CheckBitConverter(msw, lsw))
            {
                Debugger.Break();
            }
            return d;
#pragma warning restore 0675
        }

        private static Int64 CheckBitConverter(Int32 msw, Int32 lsw)
        {
            List<Byte> lw = new List<Byte>();
            lw.AddRange(BitConverter.GetBytes(lsw)); //lsw
            lw.AddRange(BitConverter.GetBytes(msw)); //msw

            return BitConverter.ToInt64(lw.ToArray(), 0);
        }

        private static UInt64 CheckBitConverterU(Int32 msw, Int32 lsw)
        {
            List<Byte> lw = new List<Byte>();
            lw.AddRange(BitConverter.GetBytes(lsw)); //lsw
            lw.AddRange(BitConverter.GetBytes(msw)); //msw

            return BitConverter.ToUInt64(lw.ToArray(), 0);
        }

        internal static UInt64 POP_P_STACK_2UD()
        {
            Int32 msw = Forth.POP_P_STACK();
            Int32 lsw = Forth.POP_P_STACK();

            UInt64 ud = (((UInt64)(UInt32)msw) << 32) | (UInt64)(UInt32)lsw;
            if (ud != CheckBitConverterU(msw, lsw))
            {
                Debugger.Break();
            }
            return ud;  //MSW, LSW
        }

        /// <summary>
        /// Push a Value onto the Parameter Stack.
        /// 
        /// //! 697
        /// </summary>
        internal static void PUSH_P_STACK(Int32 dat)
        {
            PARAM_STACK.Push(dat);
        }

        /// <summary>
        /// Push a Unsigned Value onto the Parameter Stack.
        /// </summary>
        internal static void PUSH_U2P_STACK(UInt32 dat)
        {
            PARAM_STACK.Push((Int32)dat);
        }
        /// <summary>
        /// Push a Double Value onto the Parameter Stack.
        /// </summary>
        internal static void PUSH_D2P_STACK(Int64 dat)
        {
            PUSH_P_STACK((Int32)(dat & 0xffffffff));     //LSW
            PUSH_P_STACK((Int32)(dat >> 32));            //MSW
        }

        /// <summary>
        /// Push an Unsigned Double Value onto the Parameter Stack.
        /// </summary>
        internal static void PUSH_UD2P_STACK(UInt64 dat)
        {
            PUSH_P_STACK((Int32)(dat & 0xffffffff));     //LSW
            PUSH_P_STACK((Int32)(dat >> 32));            //MSW
        }

        /// <summary>
        /// Push a Value onto the Return Stack.
        /// 
        /// //! 697
        /// </summary>
        internal static void PUSH_R_STACK(Int32 reg)
        {
            RETURN_STACK.Push(reg);
        }

        /// <summary>
        /// Push a Value onto the Floating Point Stack.
        /// </summary>
        internal static void PUSH_F_STACK(Double dat)
        {
            FPARAM_STACK.Push(dat);
        }

        /// <summary>
        /// Push two Values onto the Return Stack.
        /// 
        /// //! 697
        /// </summary>
        /// <param name="reg1"></param>
        /// <param name="reg2"></param>
        internal static void PUSH_2_R_STACK(Int32 reg1, Int32 reg2)
        {
            PUSH_R_STACK(reg1);
            PUSH_R_STACK(reg2);
        }

        internal static Boolean AllLibrariesLoaded = false;
        internal static List<FieldInfo> Libraries = new List<FieldInfo>();
        internal static Int32 LibraryNdx = 0;
        internal static Int32 LibraryPtr = 0;
        internal static String Library = String.Empty;

        /// <summary>
        /// Marker for Errors.
        /// </summary>
        public static String ErrorMarker = "\r\nError: ";

        /// <summary>
        /// Marker for Warning.
        /// </summary>
        public static String WarningMarker = "\r\nWarning: ";

        /// <summary>
        /// Marker for Info.
        /// </summary>
        public static String InfoMarker = "\r\nInfo: ";

        /// <summary>
        /// Marker for OK prompt.
        /// </summary>
        public static String OkMarker = " OK\r\n#4th>";

        /// <summary>
        /// Marker for Clear Screen.
        /// </summary>
        public static string CLsMarker = "DBGVIEWCLEAR";

        internal static Boolean DoInputAvailable()
        {
            if (!AllLibrariesLoaded)
            {
                return true;
            }

            if (OnKeyAvailableEvent != null)
            {
                return OnKeyAvailableEvent() || input.Count > 0;
            }
            else
            {
                return false;
            }
        }

        /// <summary>
        /// The Queue with Input characters to process.
        /// </summary>
        public static Queue<Char> input = new Queue<Char>();

        /// <summary>
        /// Get A Key from the Console/Application.
        /// </summary>
        /// <returns>A Key or 0</returns>
        internal static Char DoInputChar(Boolean buffer = true)
        {
            Char key = (Char)0;

            do
            {
                if (!AllLibrariesLoaded && input.Count == 0)
                {
#if LOADLIB
                    if (LibraryPtr == 0 && LibraryNdx < Libraries.Count)
                    {
                        //! LOAD WITH DEPENDENCIES!!!!, REMOVE FI's WHEN LOADED.

                        // Debug.Print("Loading: {0}", GetWordName(Libraries[LibraryNdx]));
                        Library = (String)Libraries[LibraryNdx].GetValue(null);
                    }

                    if (LibraryPtr < Library.Length)
                    {
                        input.Enqueue(Library[LibraryPtr++]);
                    }
                    else
#endif
                    //#warning disabled Library.cs
                    {
                        LibraryPtr = 0;
                        LibraryNdx++;
                        AllLibrariesLoaded = LibraryNdx == Libraries.Count;

                        if (AllLibrariesLoaded)
                        {
                            DumpMissingWordSetInfo();

                            //! Libraries Loaded.
                            DoOutput(String.Format(" · Loaded: {0} Words.", Dictionary.Count), true);
                            DoOutput(String.Empty, true);
                            DoOutput(OkMarker);

                            //! FindHidden = false;

                            //! Finally Load CommandLine Files, before accepting keyboard input.
                            List<String> files = new List<String>();
                            foreach (String arg in Environment.GetCommandLineArgs().Skip(1))
                            {
                                if (arg.EndsWith(".f", StringComparison.OrdinalIgnoreCase))
                                {
                                    files.Add(String.Format("CR CR LOAD-FILE \"{0}\" CR\n", arg));
                                }
                            }

                            foreach (String file in files)
                            {
                                foreach (Char ch in file)
                                {
                                    input.Enqueue(ch);
                                }
                            }
                        }
                    }

                    BUILT_IN = Forth.I2A(Dictionary.Count - 1);
                }
                else
                {
                    if (OnGetKeyEvent != null && OnKeyAvailableEvent != null)
                    {
                        while (OnKeyAvailableEvent())
                        {
                            OnGetKeyEvent(buffer);
                        }
                    }
                }

                if (input.Count > 0)
                {
                    return input.Dequeue();
                }

            } while (key == '\0');

            return key;
        }

        private static void DumpMissingWordSetInfo()
        {
            Boolean match = false;

            Debug.Print("[WordSetInfo]");
            foreach (DictionaryEntry de in Forth.Dictionary)
            {
                match = false;
                foreach (FieldInfo fi in typeof(Library).GetFields(BindingFlags.NonPublic | BindingFlags.Static))
                {
                    if (Forth.GetWordName(fi).Equals(de.Name))
                    {
                        if ((Int32)Forth.GetWordSet(fi) != 0)
                        {
                            match = true;
                            break;
                        }
                    }
                }

                foreach (FieldInfo fi in typeof(Words).GetFields(BindingFlags.NonPublic | BindingFlags.Static))
                {
                    if (Forth.GetWordName(fi).Equals(de.Name))
                    {
                        if ((Int32)Forth.GetWordSet(fi) != 0)
                        {
                            match = true;
                            break;
                        }
                    }
                }

                if (!match)
                {
                    Debug.Print("{0} is missing a WordSet Attribute", de.Name);
                }
            }
        }

        /// <summary>
        /// Enumerates available Forth Words, Initialzeds and Adds them in the correct order (based on dependencies).
        /// </summary>
        private static void AddBuiltInWords()
        {
            EnumerateBuiltInWords();

            EnumerateForthWords(typeof(Words).GetFields(BindingFlags.Static | BindingFlags.NonPublic));
            EnumerateForthWords(typeof(Library).GetFields(BindingFlags.Static | BindingFlags.NonPublic));

            Debug.Print("; Initializing and Adding Forth Words to Dictionary.");

            foreach (Lazy<DictionaryEntry> lde in LazyDictionary)
            {
                Dictionary.Add(lde.Value);

                //! Set the base address so we can actually fetch the value for other WORDS.
                if (lde.Value.Name.Equals("STATE"))
                {
                    Forth.STATE_ADDRESS = (Forth.Dictionary.IndexOf(Forth.Dictionary.Last()) << 16) + 24;
                }

                //! Set the base address so we can actually fetch the value for other WORDS.
                if (lde.Value.Name.Equals("DP"))
                {
                    Forth.DP_ADDRESS = (Forth.Dictionary.IndexOf(Forth.Dictionary.Last()) << 16) + 24;
                }

                //! Set the base address so we can actually fetch the value for other WORDS.
                if (lde.Value.Name.Equals("LATEST"))
                {
                    Forth.LATEST_ADDRESS = (Forth.Dictionary.IndexOf(Forth.Dictionary.Last()) << 16) + 24;
                }

                //! Set the base address so we can actually fetch the value for other WORDS.
                if (lde.Value.Name.Equals("BASE"))
                {
                    Forth.BASE_ADDRESS = (Forth.Dictionary.IndexOf(Forth.Dictionary.Last()) << 16) + 24;
                }

                //! Set the base address so we can actually fetch the value for other WORDS.
                if (lde.Value.Name.Equals("TRACE"))
                {
                    Forth.TRACE_ADDRESS = (Forth.Dictionary.IndexOf(Forth.Dictionary.Last()) << 16) + 24;
                }

                //! Set the base address so we can actually fetch the value for other WORDS.
                if (lde.Value.Name.Equals("SPAN"))
                {
                    Forth.SPAN_ADDRESS = (Forth.Dictionary.IndexOf(Forth.Dictionary.Last()) << 16) + 24;
                }
            }
        }

        /// <summary>
        /// Enumerates all available Forth Words in the correct order (as specified by dependencies) 
        /// but does not initialize them yet.
        /// </summary>
        private static void EnumerateBuiltInWords()
        {
            FieldInfo[] fis = typeof(Words).GetFields(BindingFlags.Static | BindingFlags.NonPublic);

            //! The Number of loaded Forth Words.
            Int32 loaded = -1;

            //! The Pass through the available Forth Words.
            Int32 pass = 1;

            globalpass++;

            //! Count available Forth Words.
            Int32 count = 0;

            //! Make Sure XYYZ, out placeholder is loaded first!
            Forth.LazyDictionary.Add(Words.XYYZ);
            LoadedWords.Add(GetDescription(typeof(Words).GetField("XYYZ", BindingFlags.Static | BindingFlags.NonPublic)));

            //! Loop until no more words are added.
            while (loaded != LoadedWords.Count)
            {
                loaded = LoadedWords.Count;

                count = 0;

                Debug.Print("[Pass_{0}.{1}]", globalpass, pass++);
                foreach (FieldInfo fi in fis)
                {
                    if (fi.FieldType.Name.Equals(typeof(Lazy<DictionaryEntry>).Name))
                    {
                        count++;

                        String Description = GetWordName(fi);

                        if (LoadedWords.Contains(Description))
                        {
                            continue;
                        }

                        List<String> Dependencies = new List<String>(GetDependencies(fi));

                        Boolean resolved = true;
                        foreach (String dependency in GetDependencies(fi))
                        {
                            if (!LoadedWords.Contains(dependency))
                            {
                                resolved = false;
                            }
                            else
                            {
                                Dependencies.Remove(dependency);
                            }
                        }

                        if (resolved)
                        {
                            Forth.LazyDictionary.Add(((Lazy<DictionaryEntry>)(fi.GetValue(null))));

                            //! Debug.Print(Description);

                            LoadedWords.Add(Description);
                        }
                        else
                        {
                            Debug.Print("; Could not (yet) load {0} due to unresolved Dependency on {1}.", Description, String.Join(", ", Dependencies));
                        }
                    }
                }

                if (loaded != LoadedWords.Count)
                {
                    Debug.Print("; Loaded {0} of the available Forth Words.", LoadedWords.Count - loaded);
                }
            }

            if (LoadedWords.Count != count)
            {
                Debug.Print("Error: Mismatch between loaded Forth Words and available Forth Words.");
            }
            else
            {
                Debug.Print("; All available Forth Words are loaded.");
            }
        }

        /// <summary>
        /// Enumerates all available Forth Words in the correct order (as specified by dependencies) 
        /// but does not initialize them yet.
        /// </summary>
        private static void EnumerateForthWords(FieldInfo[] fis)
        {
            //! The Number of loaded Forth Words.
            Int32 loaded = -1;

            //! The Pass through the available Forth Words.
            Int32 pass = 1;

            globalpass++;

            //! Count available Forth Words.
            Int32 count = LoadedWords.Count;

            //! Loop until no more words are added.
            while (loaded != LoadedWords.Count)
            {
                loaded = LoadedWords.Count;
                count = LoadedWords.Count;

                Debug.Print("[Pass_{0}.{1}]", globalpass, pass++);
                foreach (FieldInfo fi in fis)
                {
                    if (fi.FieldType.Name.Equals(typeof(String).Name))
                    {
                        String Description = GetWordName(fi);

                        if (LoadedWords.Contains(Description))
                        {
                            continue;
                        }

                        List<String> Dependencies = new List<String>(GetDependencies(fi));

                        Boolean resolved = true;
                        foreach (String dependency in GetDependencies(fi))
                        {
                            if (!LoadedWords.Contains(dependency))
                            {
                                resolved = false;
                            }
                            else
                            {
                                Dependencies.Remove(dependency);
                            }
                        }

                        if (resolved)
                        {
                            count++;

                            Forth.Libraries.Add(fi);

                            LoadedWords.Add(Description);
                        }
                        else
                        {
                            Debug.Print("; Could not (yet) load {0} due to unresolved Dependency on {1}.", Description, String.Join(", ", Dependencies));
                        }
                    }
                }

                if (loaded != LoadedWords.Count)
                {
                    Debug.Print("; Loaded {0} of the available Forth Words.", LoadedWords.Count - loaded);
                }
            }

            if (LoadedWords.Count != count)
            {
                Debug.Print("Error: Mismatch between loaded Forth Words and available Forth Words.");
            }
            else
            {
                Debug.Print("; All available Forth Words are loaded.");
            }
        }

        internal static Char SkipComment()
        {
            Char key = Forth.DoInputChar();

            do
            {
                while (Char.IsWhiteSpace(key) || key == '\0' || key == '\t' || key == '\r')
                {
                    key = Forth.DoInputChar();
                }

                if (key == '\\')
                {
                    while (key != '\n')
                    {
                        key = Forth.DoInputChar();
                    }

                    key = Forth.DoInputChar();

                    while (key == '\r')
                    {
                        key = Forth.DoInputChar();
                    }
                }
            } while (key == '\\');

            return key;
        }

        /// <summary>
        /// Retrieve a Web Page.
        /// 
        /// Adapted from http://www.csharp-station.com/HowTo/HttpWebFetch.aspx
        /// </summary>
        /// <param name="url">The Url to retrieve</param>
        /// <returns>The content of the retrieved webpage or null if an arror has occurred</returns>
        internal static String GetWebPage(Uri url)
        {
            return GetWebPage(url, null, null);
        }

        internal static String GetWebPage(Uri url, String UserName, String Password)
        {
            //Used to build entire input.
            StringBuilder sb = new StringBuilder();

            try
            {
                //Used on each read operation.
                byte[] buf = new byte[8192];

                //Prepare the web page we will be asking for.
                HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
                //request.AllowAutoRedirect = true;

                if (!(String.IsNullOrEmpty(UserName) && String.IsNullOrEmpty(Password)))
                {
                    //CredentialCache cc = new CredentialCache();
                    //cc.Add(url, "Basic", new NetworkCredential(UserName, Password));
                    request.Credentials = new NetworkCredential(UserName, Password);//cc;
                    request.PreAuthenticate = true;
                }

                //Execute the request.
                HttpWebResponse response = (HttpWebResponse)request.GetResponse();

                //Read data via the response stream.
                Stream reader = response.GetResponseStream();

                DoOutput("{0} {1}\r\n", (Int32)response.StatusCode, response.StatusDescription);

                string tempString = null;
                int count = 0;

                do
                {
                    //Fill the buffer with data.
                    count = reader.Read(buf, 0, buf.Length);

                    //Make sure we read some data.
                    if (count != 0)
                    {
                        //Translate from bytes to UTF8 text (ASCII will Fail!).
                        tempString = Encoding.UTF8.GetString(buf, 0, count);

                        //Continue building the string.
                        sb.Append(tempString);
                    }
                }
                while (count > 0); // any more data to read?

                reader.Close();
                response.Close();
            }
            catch (Exception e)
            {
                Debug.Print(e.Message);

                return null;
            }

            //Return response source.
            return sb.ToString();
        }

        #endregion Methods
    }

    ///// <summary>
    ///// Simple Union between Int32 and 4 Bytes/Single
    ///// </summary> 
    //[StructLayout(LayoutKind.Explicit, Size = 4)]
    //public struct Int32SingleUnion : IDisposable
    //{
    //    /// <summary>
    //    /// the Single value.
    //    /// </summary>
    //    [FieldOffset(0)]
    //    public Single sVal;

    //    /// <summary>
    //    /// the Int32 value.
    //    /// </summary>
    //    [FieldOffset(0)]
    //    public Int32 iVal;

    //    /// <summary>
    //    /// Constructor.
    //    /// </summary>
    //    /// <param name="sVal"></param>
    //    public Int32SingleUnion(Single sVal)
    //    {
    //        this.iVal = 0;
    //        this.sVal = sVal;
    //    }

    //    /// <summary>
    //    /// Constructor.
    //    /// </summary>
    //    /// <param name="iVal"></param>
    //    public Int32SingleUnion(Int32 iVal)
    //    {
    //        this.sVal = 0;
    //        this.iVal = iVal;
    //    }

    //    #region IDisposable Members

    //    /// <summary>
    //    /// Dispose().
    //    /// </summary>
    //    void IDisposable.Dispose()
    //    {
    //        //this.Dispose();
    //    }

    //    #endregion
    //}

    /// <summary>
    /// Simple Union between Int32 and 4 Bytes.
    /// </summary> 
    [StructLayout(LayoutKind.Explicit, Size = 4)]
    public struct Int32ByteUnion : IDisposable
    {
        /// <summary>
        /// lsb, 1 &lt;&lt; 0, last character/byte stored.
        /// </summary>
        [FieldOffset(0)]
        public byte byte3;

        /// <summary>
        /// 1 &lt;&lt; 8
        /// </summary>
        [FieldOffset(1)]
        public byte byte2;

        /// <summary>
        /// 1 &lt;&lt; 16
        /// </summary>
        [FieldOffset(2)]
        public byte byte1;

        /// <summary>
        /// msb 1 &lt;&lt; 24, first character/byte stored.
        /// </summary>
        [FieldOffset(3)]
        public byte byte0;

        /// <summary>
        /// the Int32 value.
        /// </summary>
        [FieldOffset(0)]
        public Int32 iVal; //msb 1<<24

        /// <summary>
        /// Constructor.
        /// </summary>
        /// <param name="iVal">The Integer value to convert</param>
        public Int32ByteUnion(Int32 iVal)
        {
            this.byte0 = 0;
            this.byte1 = 0;
            this.byte2 = 0;
            this.byte3 = 0;

            this.iVal = iVal;
        }

        /// <summary>
        /// Access to the 4 Bytes.
        /// </summary>
        /// <param name="index">The byte index</param>
        /// <returns>The byte</returns>
        public byte this[Int32 index]
        {
            get
            {
                switch (index % 4)
                {
                    case 0:
                        return byte0;
                    case 1:
                        return byte1;
                    case 2:
                        return byte2;
                    case 3:
                        return byte3;
                    default:
                        // Should not happen.
                        Forth.DoOutput(Forth.ErrorMarker + "Byte Index of Range (0..3)", true);
                        return 0;
                }
            }
            set
            {
                switch (index % 4)
                {
                    case 0:
                        byte0 = value;
                        break;
                    case 1:
                        byte1 = value;
                        break;
                    case 2:
                        byte2 = value;
                        break;
                    case 3:
                        byte3 = value;
                        break;
                    default:
                        // Should not happen.
                        Forth.DoOutput(Forth.ErrorMarker + "Byte Index of Range (0..3)", true);
                        break;
                }
            }
        }

        /// <summary>
        /// Conveniance during Debugging.
        /// </summary>
        /// <returns>A String</returns>
        public override String ToString()
        {
            return String.Format("0x{0:x8} : [0x{1:x2}, 0x{2:x2}, 0x{3:x2}, 0x{4:x2}]", iVal, byte0, byte1, byte2, byte3);
        }

        #region IDisposable Members

        /// <summary>
        /// Dispose().
        /// </summary>
        void IDisposable.Dispose()
        {
            //this.Dispose();
        }

        #endregion
    }

    /// <summary>
    /// Used for ABORT Word.
    /// </summary>
    [Serializable]
    public class AbortException : Exception
    {
        /// <summary>
        /// The Forth THROW Code.
        /// </summary>
        public Int32 Code
        {
            get;
            private set;
        }

        /// <summary>
        /// Constructor.
        /// </summary>
        public AbortException()
        {
            this.Code = 0;
        }

        /// <summary>
        /// Constructor.
        /// </summary>
        /// <param name="message"></param>
        public AbortException(String message)
            : base(message)
        {
            this.Code = 0;
        }

        /// <summary>
        /// Constructor.
        /// </summary>
        /// <param name="Code">The Forth THROW Code</param>
        /// <param name="message"></param>
        public AbortException(Int32 Code, String message = "")
            : base(message)
        {
            this.Code = Code;
        }

        /// <summary>
        /// Constructor.
        /// </summary>
        /// <param name="info"></param>
        /// <param name="context"></param>
        protected AbortException(SerializationInfo info, StreamingContext context)
            : base(info, context)
        {
            this.Code = 0;
        }
    }
}